use rusqlite::ToSql;
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, ValueRef};
use serde::{Deserialize, Serialize};

#[derive(Debug, Default, Clone, Serialize, Deserialize, Eq, PartialEq)]
pub(crate) enum ComponentV2rayServerNetwork {
    #[default]
    Tcp,
    Kcp,
    WebSocket,
    Http,
    Quic,
}

impl ComponentV2rayServerNetwork {
    pub(crate) fn to_v2ray_network(&self) -> String {
        match self {
            ComponentV2rayServerNetwork::Tcp => "tcp".to_string(),
            ComponentV2rayServerNetwork::Kcp => "kcp".to_string(),
            ComponentV2rayServerNetwork::WebSocket => "ws".to_string(),
            ComponentV2rayServerNetwork::Http => "http".to_string(),
            ComponentV2rayServerNetwork::Quic => "quic".to_string(),
        }
    }
}

impl ToSql for ComponentV2rayServerNetwork {
    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
        match *self {
            ComponentV2rayServerNetwork::Tcp => Ok(ToSqlOutput::Owned(rusqlite::types::Value::Text("Tcp".to_string()))),
            ComponentV2rayServerNetwork::Kcp => Ok(ToSqlOutput::Owned(rusqlite::types::Value::Text("Kcp".to_string()))),
            ComponentV2rayServerNetwork::WebSocket => Ok(ToSqlOutput::Owned(rusqlite::types::Value::Text("WebSocket".to_string()))),
            ComponentV2rayServerNetwork::Http => Ok(ToSqlOutput::Owned(rusqlite::types::Value::Text("Http".to_string()))),
            ComponentV2rayServerNetwork::Quic => Ok(ToSqlOutput::Owned(rusqlite::types::Value::Text("Quic".to_string()))),
        }
    }
}

impl FromSql for ComponentV2rayServerNetwork {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        match value.as_str() {
            Ok("Tcp") => Ok(ComponentV2rayServerNetwork::Tcp),
            Ok("Kcp") => Ok(ComponentV2rayServerNetwork::Kcp),
            Ok("WebSocket") => Ok(ComponentV2rayServerNetwork::WebSocket),
            Ok("Http") => Ok(ComponentV2rayServerNetwork::Http),
            Ok("Quic") => Ok(ComponentV2rayServerNetwork::Quic),
            _ => Err(FromSqlError::InvalidType),
        }
    }
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub(crate) struct ComponentV2rayServerWebsocketSetting {
    pub(crate) path: String,
    pub(crate) headers_json_string: String,
}

impl ToSql for ComponentV2rayServerWebsocketSetting {
    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
        Ok(ToSqlOutput::Owned(rusqlite::types::Value::Text(serde_json::to_string(&self).unwrap())))
    }
}

impl FromSql for ComponentV2rayServerWebsocketSetting {
    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
        Ok(serde_json::from_str(&value.as_str().unwrap()).unwrap())
    }
}

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub(crate) struct ComponentV2rayServer {
    pub(crate) uuid: String,
    pub(crate) tag: String,
    pub(crate) address: String,
    pub(crate) port: u16,
    pub(crate) user_id: String,
    pub(crate) alter_id: i32,
    pub(crate) level: i32,
    pub(crate) security: String,
    pub(crate) network: ComponentV2rayServerNetwork,
    pub(crate) websocket_setting: ComponentV2rayServerWebsocketSetting,
    pub(crate) used: bool,
}